﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Diagnostics;
using System.Windows.Forms;
using System.Xml;
using System.IO;


namespace VoltcraftControlInterface
{
    public partial class HeatIntegrator : Form
    {
        string editmode;
        MainForm mainForm;
        bool shouldlog;
        Stopwatch logger;
        public DataTable listofmediums;
        PolynomialIntegrator poli;
        public delegate void SetVDel(double T2, double T1, double t2, double t1);
        public void SetValues(double T2, double T1, double t2, double t1)
        {
            if (this.heatbalanceBox.InvokeRequired)
            {
                SetVDel d = new SetVDel(SetValues);
                Invoke(d, new object[] { T2, T1, t2, t1 });
            }
            else
            {
                DataRow[] resultrow = listofmediums.Select("Name Like '" + mediumList.Text + "'");
                if (resultrow.Length > 0)
                {
                    poli.IntegrateAndCalculate(resultrow[0]["Expression"].ToString(), T2, T1, t2, t1);
                    heatbalanceBox.Text = String.Format("{0:0.000}", (Convert.ToDouble(heatbalanceBox.Text) + poli.DeltaQ));
                    powerBox.Text = poli.Pow.ToString("F3");
                    if (shouldlog)
                    {
                        double nowtime = logger.Elapsed.TotalSeconds + logger.Elapsed.Milliseconds / 1000;
                        chart1.Series[0].Points.AddXY(nowtime, Convert.ToDouble(heatbalanceBox.Text), DateTime.Now.ToOADate());
                        chart1.Series[1].Points.AddXY(nowtime, Convert.ToDouble(poli.Pow));
                    }
                }
            }
        }
        public System.Windows.Forms.DataVisualization.Charting.Chart chart1Ext
        {
            get { return this.chart1; }
            set { this.chart1 = value; }
        }
        public HeatIntegrator(Form iform)
        {
            InitializeComponent();
            shouldlog = false;
            logger = new Stopwatch();
            mainForm = iform as MainForm;
            poli = new PolynomialIntegrator();
            listofmediums = new DataTable();
            listofmediums.Clear();
            listofmediums.Columns.Add("Name");
            listofmediums.Columns.Add("Expression");
            string appdataDir = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),"InstruMan\\");
            if (!Directory.Exists(appdataDir)) Directory.CreateDirectory(appdataDir);
            if (!File.Exists(Path.Combine(appdataDir, "settings.xml")))
            {
                XmlDocument newdoc = new XmlDocument();
                XmlDeclaration xmlDeclaration = newdoc.CreateXmlDeclaration("1.0", "UTF-8", null);
                XmlElement root = newdoc.DocumentElement;
                newdoc.InsertBefore(xmlDeclaration, root);
                XmlElement xmlroot = newdoc.CreateElement(string.Empty, "Materials", string.Empty);
                newdoc.AppendChild(xmlroot);

                XmlElement airentry = newdoc.CreateElement(string.Empty, "Entry", string.Empty);
                airentry.SetAttribute("name", "Air");
                airentry.SetAttribute("expression", "-4,91e-11x^4+7,659e-8x^3-4,369e-5x^2+1,089e-2x^1+4,161e-6");
                xmlroot.AppendChild(airentry);

                XmlElement waterentry = newdoc.CreateElement(string.Empty, "Entry", string.Empty);
                waterentry.SetAttribute("name", "Water");
                waterentry.SetAttribute("expression", "-7,617e-10x^4+9,0322e-7x^3-3,841e-4x^2+6,844e-2x^1+1,297e-6");
                xmlroot.AppendChild(waterentry);
                try
                {
                    newdoc.Save(Path.Combine(appdataDir, "settings.xml"));
                }
                catch (UnauthorizedAccessException)
                {
                    MessageBox.Show("Settings file corrupted or deleted! Restart application with Administrator privileges to repair", "Error!", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    Application.Exit();
                }
            }
            try
            {
                XmlDocument settings = new XmlDocument();
                settings.Load(Path.Combine(appdataDir, "settings.xml"));
                if (settings.HasChildNodes)
                {
                    XmlNode rootnode = settings.SelectSingleNode("Materials");
                    if (rootnode.HasChildNodes)
                    {
                        XmlNodeList entries = rootnode.SelectNodes("Entry");

                        string name = "";
                        string expression = "";
                        for (int i = 0; i < entries.Count; i++)
                        {
                            name = entries[i].Attributes["name"].Value;
                            expression = entries[i].Attributes["expression"].Value;
                            if ((name != "") && (expression != ""))
                            {
                                DataRow newrow = listofmediums.NewRow();
                                newrow["Name"] = name;
                                newrow["Expression"] = expression;
                                listofmediums.Rows.Add(newrow);
                                mediumList.Items.Add(name);
                            }
                        }
                        mediumList.SelectedIndex = 0;
                    }
                    else throw new System.ArgumentException("XML file does not contain values to initiate settings");
                }
                else throw new System.ArgumentException("Bad XML file");
            }
            catch
            {
                /*MessageBox.Show("Bad XML settings file! Delete it manually and restart application!", "Error!", MessageBoxButtons.OK, MessageBoxIcon.Error);
                Environment.FailFast("Error while loading XML settings file"+Environment.NewLine+e);*/
                File.Delete(Path.Combine(appdataDir, "settings.xml"));
                XmlDocument newdoc = new XmlDocument();
                XmlDeclaration xmlDeclaration = newdoc.CreateXmlDeclaration("1.0", "UTF-8", null);
                XmlElement root = newdoc.DocumentElement;
                newdoc.InsertBefore(xmlDeclaration, root);
                XmlElement xmlroot = newdoc.CreateElement(string.Empty, "Materials", string.Empty);
                newdoc.AppendChild(xmlroot);

                XmlElement airentry = newdoc.CreateElement(string.Empty, "Entry", string.Empty);
                airentry.SetAttribute("name", "Air");
                airentry.SetAttribute("expression", "-4,91e-11x^4+7,659e-8x^3-4,369e-5x^2+1,089e-2x^1+4,161e-6");
                xmlroot.AppendChild(airentry);

                XmlElement waterentry = newdoc.CreateElement(string.Empty, "Entry", string.Empty);
                waterentry.SetAttribute("name", "Water");
                waterentry.SetAttribute("expression", "-7,617e-10x^4+9,0322e-7x^3-3,841e-4x^2+6,844e-2x^1+1,297e-6");
                xmlroot.AppendChild(waterentry);
                newdoc.Save(Path.Combine(appdataDir, "settings.xml"));
                try
                {
                    XmlDocument settings = new XmlDocument();
                    settings.Load(Path.Combine(appdataDir, "settings.xml"));
                    if (settings.HasChildNodes)
                    {
                        XmlNode rootnode = settings.SelectSingleNode("Materials");
                        if (rootnode.HasChildNodes)
                        {
                            XmlNodeList entries = rootnode.SelectNodes("Entry");

                            string name = "";
                            string expression = "";
                            for (int i = 0; i < entries.Count; i++)
                            {
                                name = entries[i].Attributes["name"].Value;
                                expression = entries[i].Attributes["expression"].Value;
                                if ((name != "") && (expression != ""))
                                {
                                    DataRow newrow = listofmediums.NewRow();
                                    newrow["Name"] = name;
                                    newrow["Expression"] = expression;
                                    listofmediums.Rows.Add(newrow);
                                    mediumList.Items.Add(name);
                                }
                            }
                            mediumList.SelectedIndex = 0;
                        }
                        else throw new System.ArgumentException("XML file does not contain values to initiate settings");
                    }
                    else throw new System.ArgumentException("Bad XML file");
                }
                catch (System.Exception e)
                {
                    MessageBox.Show("Bad XML settings file! Delete it manually and restart application!", "Error!", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    Environment.FailFast("Error while loading XML settings file" + Environment.NewLine + e);
                }
            }
            /*DataRow air = listofmediums.NewRow();
            air["Name"] = "Air";
            air["Expression"] = "-4,91e-11x^4+7,659e-8x^3-4,369e-5x^2+1,089e-2x^1+4,161e-6";
            listofmediums.Rows.Add(air);
            DataRow water = listofmediums.NewRow();
            water["Name"] = "Water";
            water["Expression"] = "-7,617e-10x^4+9,0322e-7x^3-3,841e-4x^2+6,844e-2x^1+1,297e-6";
            listofmediums.Rows.Add(water);*/
        }

        private void Form3_Load(object sender, EventArgs e)
        {
            editmode = "";
            inputPnl.Location = new Point(-156, inputPnl.Location.Y);
        }

        private void Form3_FormClosing(object sender, FormClosingEventArgs e)
        {
            this.Hide();
            e.Cancel = true;
        }

        private void button1_Click(object sender, EventArgs e)
        {
            Double maxval = 0;
            if (chart1.Series[0].Points.Count > 0) maxval = chart1.ChartAreas[0].AxisX.Maximum;
            if (logger.Elapsed.Seconds >= maxval)
            {
                logger.Start();
                shouldlog = true;
                tsbutton1.Enabled = false;
                tsbutton2.Enabled = true;
            }
            else
            {
                MessageBox.Show("Can't overwrite old chart data! First clear the chart or create a new experiment", "Error!", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
            }
        }

        private void button2_Click(object sender, EventArgs e)
        {
            shouldlog = false;
            logger.Stop();
            tsbutton1.Enabled = true;
            tsbutton2.Enabled = false;
        }

        private void button3_Click(object sender, EventArgs e)
        {
            SaveFileDialog filepath = new SaveFileDialog();
            filepath.Filter = "CSV Spreadsheet|*.csv";
            filepath.Title = "Save Logged Data";
            filepath.ShowDialog();
            if (filepath.FileName != "")
            {
                if (System.IO.File.Exists(filepath.FileName)) System.IO.File.Delete(filepath.FileName);
                using (System.IO.StreamWriter file =
              new System.IO.StreamWriter(@filepath.FileName, true))
                {
                        file.WriteLine("Time(s);Time;Heat Balance (kJ/kg);Instant Power (kW/kg)");
                        for (int i = 0; i < chart1.Series[0].Points.Count; i++)
                        {
                            //parsetime = DateTime.FromOADate(logChart.Series["Voltage"].Points[i].XValue);
                            file.WriteLine(chart1.Series[0].Points[i].XValue + ";"+ DateTime.FromOADate(chart1.Series[0].Points[i].YValues[1]).ToLongTimeString()+"."+ DateTime.FromOADate(chart1.Series[0].Points[i].YValues[1]).Millisecond + ";" + chart1.Series[0].Points[i].YValues[0].ToString("F3") + ";" + chart1.Series[1].Points[i].YValues[0].ToString("F3"));
                        }
                    file.Close();
                }
            }
            
        }

        private void button4_Click(object sender, EventArgs e)
        {
            chart1.Series[0].Points.Clear();
            chart1.Series[1].Points.Clear();
            heatbalanceBox.Text = "0";
            powerBox.Text = "0";
            logger.Reset();
        }

        private void addPolynomialInterpolatedFunctionToolStripMenuItem_Click(object sender, EventArgs e)
        {
            //InputClass input = new InputClass();
            if (!okBtn.Enabled)
            {
                exprBox.Text = "Ax^n+Bx^(n-1)+Cx^(n-2)+...+D";
                matBox.Text = "Material Name";
                editmode = "add";
                /*if (input.InputBox("Input", "Insert name of material", "Insert interpolated expression", ref returnname, ref returnexpr, this) != DialogResult.Cancel)
                {
                    if ((returnexpr != "") && (returnname != ""))
                    {
                        DataRow newrow = listofmediums.NewRow();
                        newrow["Name"] = returnname;
                        newrow["Expression"] = returnexpr;
                        listofmediums.Rows.Add(newrow);
                        mediumList.Items.Add(returnname);
                    }
                }*/
                okBtn.Enabled = true;
                cancBtn.Enabled = true;
                addTsBtn.Enabled = false;
                delTsBtn.Enabled = false;
                editTsBtn.Enabled = false;
                clrTsBtn.Enabled = false;
                Pnl pnlAnim = new Pnl();
                pnlAnim.openPnl(ref inputPnl);
            }
        }

        private void toolsToolStripMenuItem_Click(object sender, EventArgs e)
        {

        }

        private void deleteSelectedEntryInMaterialsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if(mediumList.Text != "")
            {
                DataRow todelete = listofmediums.Select("Name = '" + mediumList.Text+"'")[0];
                listofmediums.Rows.Remove(todelete);
                mediumList.Items.RemoveAt(mediumList.SelectedIndex);
            }
        }

        private void deleteALLentriesInMaterialsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if(MessageBox.Show("Are you sure you want to delete all entries of materials list?", "Warning!", MessageBoxButtons.YesNo, MessageBoxIcon.Warning)==DialogResult.Yes)
            {
                listofmediums.Rows.Clear();
                mediumList.Items.Clear();
            }
        }

        private void toolStripButton4_Click(object sender, EventArgs e)
        {
            if (!okBtn.Enabled)
            {
                DataRow[] resultrow = listofmediums.Select("Name = '" + mediumList.Text + "'");
                if (resultrow.Length > 0)
                {
                    exprBox.Text = resultrow[0]["Expression"].ToString();
                    matBox.Text = resultrow[0]["Name"].ToString();
                    editmode = "edit";
                    Pnl anim = new Pnl();
                    anim.openPnl(ref inputPnl);
                    okBtn.Enabled = true;
                    cancBtn.Enabled = true;
                    addTsBtn.Enabled = false;
                    delTsBtn.Enabled = false;
                    editTsBtn.Enabled = false;
                    clrTsBtn.Enabled = false;
                }
            } 
                /*InputClass input = new InputClass();
                if (input.InputBox("Input", "Insert name of material", "Insert interpolated expression", ref returnname, ref returnexpr, this) != DialogResult.Cancel)
                {
                    if ((returnexpr != "") && (returnname != ""))
                    {
                        DataRow newrow = listofmediums.NewRow();
                        newrow["Name"] = returnname;
                        newrow["Expression"] = returnexpr;
                        listofmediums.Rows.Remove(resultrow[0]);
                        listofmediums.Rows.Add(newrow);
                        mediumList.Items[mediumList.SelectedIndex] = returnname;
                    }
                }
            }*/

        }

        private void okBtn_Click(object sender, EventArgs e)
        {
            if ((matBox.Text != "") && (exprBox.Text != ""))
            {
                if (editmode == "add")
                {
                    DataRow newrow = listofmediums.NewRow();
                    newrow["Name"] = matBox.Text;
                    newrow["Expression"] = exprBox.Text;
                    listofmediums.Rows.Add(newrow);
                    mediumList.Items.Add(matBox.Text);
                }
                else if (editmode == "edit")
                {
                    DataRow[] resultrow = listofmediums.Select("Name = '" + mediumList.Text + "'");
                    DataRow newrow = listofmediums.NewRow();
                    newrow["Name"] = matBox.Text;
                    newrow["Expression"] = exprBox.Text;
                    listofmediums.Rows.Remove(resultrow[0]);
                    listofmediums.Rows.Add(newrow);
                    mediumList.Items[mediumList.SelectedIndex] = matBox.Text;
                }
            }
            okBtn.Enabled = false;
            cancBtn.Enabled = false;
            Pnl anim = new Pnl();
            anim.closePnl(ref inputPnl);
            editmode = "";
            addTsBtn.Enabled = true;
            delTsBtn.Enabled = true;
            editTsBtn.Enabled = true;
            clrTsBtn.Enabled = true;
        }

        private void cancBtn_Click(object sender, EventArgs e)
        {
            Pnl anim = new Pnl();
            anim.closePnl(ref inputPnl);
            okBtn.Enabled = false;
            cancBtn.Enabled = false;
            editmode = "";
            addTsBtn.Enabled = true;
            delTsBtn.Enabled = true;
            editTsBtn.Enabled = true;
            clrTsBtn.Enabled = true;
        }

        private void button1_Click_1(object sender, EventArgs e)
        {
            MessageBox.Show("You can use only polynomial expression of x, always indicating coefficient and power of x" + Environment.NewLine +
                "Example: if you need to write the variable x (coefficient 1 and power 1), you must write 1x^1" + Environment.NewLine +
                "You can write numbers in scientific notation, for example for 3*10^5 you write 3e5, for 2*10^(-6) you write 2e-6","Help",MessageBoxButtons.OK,MessageBoxIcon.Information);
        }
    }
}
